package com.saunter.service.user;

import com.alibaba.fastjson.JSON;
import com.saunter.extendMapper.AdminExtendMapper;
import com.saunter.extendModel.UserExtend;
import com.saunter.model.Admin;
import com.saunter.model.Company;
import com.saunter.model.Theme;
import com.saunter.model.User;
import com.saunter.service.CompanyService;
import com.saunter.service.ThemeService;
import com.saunter.utils.ConfigProperties;
import com.saunter.utils.CookieUtils;
import com.saunter.utils.Util;
import com.saunter.utils.encrypt.Md5Encrypt;
import com.saunter.utils.excel.ExcelData;
import com.saunter.utils.excel.ExportExcelUtils;
import com.saunter.utils.excel.ImportExcelUtils;
import com.saunter.utils.exception.ExceptionManager;
import com.saunter.utils.response.CustomPage;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

@Service("AdminService")
public class AdminService extends SuperUserService implements SuperUserServiceInterf {
    @Autowired
    private AdminExtendMapper adminExtendMapper;
    @Resource
    private ExceptionManager exceptionManager;
    @Autowired
    private UserService userService;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private ThemeService themeService;
    @Autowired
    private ConfigProperties configProperties;

    public void removeCookie(HttpServletResponse response) {
        CookieUtils.removeAdminCookie(response, "sid");
    }
    protected String createAdminJwt(String user_id) {
        return super.createAdminJwt("admin_id", user_id);
    }
    public Map<String, String> login(String email, String passwd) {
        Admin admin = adminExtendMapper.getByEmail(email);
        Map<String, String> res = new HashMap<String, String>();

        if(null == admin) {
            res.put("err_code", "Lg001");
        }else{
            if(Md5Encrypt.encrypt(passwd).equals(admin.getPasswd())) {
                Integer user_id = admin.getId();
                res.put("sid", this.createAdminJwt(""+user_id));
            }else {
                res.put("err_code", "Lg002");
                throw exceptionManager.create("Lg002");
            }
        }
        return res;
    }

    public String getUserDefaultPasswd() {
        String default_passwd = configProperties.getUser_default_password();
        return null != default_passwd ? default_passwd : "ab1234567";
    }
    public String setUserDefaultPw(String user_default_pw) {
        if(!Util.verifyPasswordFormat(user_default_pw)) {
            return "Prm_password";
        }
        if(user_default_pw.equals(this.getUserDefaultPasswd())) {
            return "Prm004";
        }
        configProperties.setUser_default_password(user_default_pw);
        return "1";
    }

    public String getEncryptKey() {
        String encrypt_key = configProperties.getEncrypt_key();
        return null != encrypt_key ? encrypt_key : "ab1234567";
    }
    public String setEncryptKey(String encrypt_key) {
        if(!Util.verifyPasswordFormat(encrypt_key)) {
            return "Prm_password";
        }
        if(encrypt_key.equals(this.getEncryptKey())) {
            return "Prm004";
        }
        configProperties.setEncrypt_key(encrypt_key);
        return "1";
    }

    public boolean isShowUserJob() {
        return configProperties.isShow_user_job();
    }
    public String setShowUserJob(boolean show_user_job) {
        if(show_user_job == this.isShowUserJob()) {
            return "Prm004";
        }
        configProperties.setShow_user_job(show_user_job);
        return "1";
    }

    public Boolean checkPasswd(Integer int_admin_id, String passwd) {
        if(null == int_admin_id || "".equals(int_admin_id.toString()) || null == passwd || "".equals(passwd)) {
            return false;
        }else {
            return Md5Encrypt.encrypt(passwd).equals(adminExtendMapper.selectByPrimaryKey(int_admin_id).getPasswd());
        }
    }
    public String checkSecondPasswd(Integer int_admin_id, String second_passwd) {
        if(null != int_admin_id) {
            Admin admin = adminExtendMapper.selectByPrimaryKey(int_admin_id);
            return Md5Encrypt.encrypt(second_passwd).equals(admin.getSecondPasswd()) ? "1" : "Lg003";
        }else {
            return "Lg000";
        }
    }
    public int editAdmin(Admin admin) {
        String admin_email = admin.getEmail();
        String passwd = admin.getPasswd();
        String second_passwd = admin.getSecondPasswd();
        String name = admin.getName();
        Admin old_admin = adminExtendMapper.selectByPrimaryKey(admin.getId());
        if(null == old_admin) {
            throw exceptionManager.create("Lg001");
        }
        if(null != admin_email && !Util.verifyEmail(admin_email)) {
            throw exceptionManager.create("Prm_email");
        }
        if(null != second_passwd && !Util.verifyPasswordFormat(second_passwd) || (null != passwd && !Util.verifyPasswordFormat(passwd))) {
            throw exceptionManager.create("Prm_password");
        }
        if(null != name && "".equals(name.trim())) {
            throw exceptionManager.create("Prm005");
        }
        if(null != passwd) {
            passwd = Md5Encrypt.encrypt(passwd);
            admin.setPasswd(passwd);
        }
        if(null != second_passwd) {
            second_passwd = Md5Encrypt.encrypt(second_passwd);
            admin.setSecondPasswd(second_passwd);
        }
        if(null != name && name.equals(old_admin.getName()) ||null != admin_email && admin_email.equals(old_admin.getEmail()) || (null != passwd && passwd.equals(old_admin.getPasswd())) || (null != second_passwd && second_passwd.equals(old_admin.getSecondPasswd()))){
            throw exceptionManager.create("Prm004");
        }

        return adminExtendMapper.updateByPrimaryKeySelective(admin);
    }
    public int addUser(User user) {
        if(null == user.getPasswd()) {
            user.setPasswd(Md5Encrypt.encrypt(this.getUserDefaultPasswd()));
        }
        return userService.add(user);
    }

    public CustomPage<User> getUsers(int page_no, int page_size) {
        return userService.getAll(page_no, page_size);
    }
    public CustomPage<UserExtend> getUsersAndJob(int page_no, int page_size, Map<String, Object> filters) {
        return userService.getAllAndJob(page_no, page_size, filters);
    }

    public int editUser(User user) {
        return userService.editUser(user);
    }

    public int deleteUser(String id_num) {
        return userService.deleteById(id_num);
    }

    public int resetUserPasswd(String id_num) {
        return userService.setPasswd(id_num, this.getUserDefaultPasswd());
    }

    public int exportUsers(HttpServletResponse response, Map<String, Object> filters) throws Exception {
        List<UserExtend> users = userService.getAllAndJob(filters);
        ExcelData excelData = new ExcelData();
        excelData.setName("user");
        List<String> titles = new ArrayList<String>(){{
            add("序号");add("工号");add("姓名");add("生日");add("性别");add("手机号");add("邮箱");add("部门");add("职位");add("创建时间");add("备注");add("状态");
        }};
        excelData.setTitles(titles);
        List<List<Object>> data_body = new ArrayList<List<Object>>();
        List<Object> row_data;

        UserExtend user;
        for(int i_index = 0; i_index< users.size(); i_index ++) {
            row_data = new ArrayList<Object>();
            row_data.add(i_index + 1);
            user = users.get(i_index);
            row_data.add(user.getIdNum());
            row_data.add(user.getName());
            row_data.add(user.getBirthdate().toString());
            row_data.add(user.getSex().equals(2) ? "女":"男");
            row_data.add(user.getPhone());
            row_data.add(user.getEmail());
            try {
                row_data.add(user.getJob().getDepartment().getName());
            }catch (Exception e) {
                row_data.add("");
            }
            try {
                row_data.add(user.getJob().getName());
            }catch (Exception e) {
                row_data.add("");
            }
            row_data.add(user.getCreateTime().toString());
            row_data.add(user.getRemark());
            row_data.add(user.getStatus().equals(1)?"在职":"离职");
            data_body.add(row_data);
        }
        excelData.setRows(data_body);
        ExportExcelUtils.exportExcel(response,"user.xlsx",excelData);
        return 1;
    }

    public int importUsers(MultipartFile file, Integer job_id) throws IOException {
        ExcelData excelData = ImportExcelUtils.loadExcelFile(file.getInputStream(), "user");
        if(null == excelData) {
            throw exceptionManager.create("File005");
        }else {
            Map<String, Map<String, String>> excel_right_data = this.checkExcelAndGetUserDatas(excelData);
            userService.insertByMap(new ArrayList<Map<String, String>>(excel_right_data.values()), Md5Encrypt.encrypt(this.getUserDefaultPasswd()), job_id);
        }
        return 1;
    }

    /**
     * 检测excelData的数据的正确性
     * @param excelData
     * @return 正确的可插入数据库的记录数据
     */
    public Map<String, Map<String, String>> checkExcelAndGetUserDatas(ExcelData excelData) {
        //获取salary_key的信息，用于之后的检测

        //Excel标题检测（带顺序检测）
        List<String> excel_title = excelData.getTitles();
        if(!this.getUserExcelTitles().equals(excel_title)){
            throw exceptionManager.create("Sal004");
        }
        List<String> excel_keys = this.getUserExcelKeys();

        //导入的有效数据：经过id_num去重和非空检验；String[0]是行的序号；String[1]是salary_data，如果有错则为空
        Map<String, Map<String, String>> serialize_data = new HashMap<String, Map<String, String>>();
        //错误信息：key是行的序号，可能重复；value是具体错误
        List<String[]> err_info = new ArrayList<String[]>();
        //判断整个检测过程有无错误
        boolean has_error = false;
        //判断每行的user_id_num是否重复
        boolean id_num_repeat = false;
        //暂存行的值
        List<Object> excel_row;
        //暂存列的值和列的序号（可能与列的index不相等）及列的key
        Object cell_data;
        String cell_str, excel_index="", excel_key="", cell_err_str;
        //暂存导入的user_data，为之后的JSON序列化提供数据
        Map<String, String> user_data;

        List<List<Object>> excel_rows = excelData.getRows();

        //为了提高效率都用基本的for循环
        for(int row_index = 0; row_index < excel_rows.size(); row_index ++ ) {
            excel_row = excel_rows.get(row_index);
            user_data = new HashMap<String, String>();
            id_num_repeat = false;
            for (int cell_index = 0; cell_index < excel_row.size(); cell_index ++ ) {
                cell_data =  excel_row.get(cell_index);
                excel_key = excel_keys.get(cell_index);
                cell_err_str = "";
                if(null == cell_data || "".equals(cell_data.toString().trim()) && !("email".equals(excel_key) || "phone".equals(excel_key) ||"remark".equals(excel_key))) {
                    if(0 == cell_index) {
                        excel_index="行"+(row_index + 1);
                    }
                    cell_err_str = excel_title.get(cell_index)+"为空";
                }else {
                    cell_str = cell_data.toString().trim();
                    if(0 == cell_index) {
                        excel_index = cell_str;
                    }else if(1 == cell_index) {
                        //id_num去重检测
                        if(serialize_data.containsKey(cell_str)) {
                            id_num_repeat = true;
                            cell_err_str = "该行的工号与序号为"+serialize_data.get(cell_str).get("index")+"的行重复";
                        }
                    }else if("sex".equals(excel_key)){
                        if("男".equals(cell_str)) {
                            cell_str = "1";
                        }else if("女".equals(cell_str)) {
                            cell_str = "2";
                        }else {
                            cell_err_str = "性别的数据格式错误：只能为男或女";
                        }
                    }else if("phone".equals(excel_key)) {
                        if(!"".equals(cell_str) && !Util.verifyPhone(cell_str)) {
                            cell_err_str = "手机格式错误";
                        }
                    }else if("email".equals(excel_key)){
                        if(!"".equals(cell_str) && !Util.verifyEmail(cell_str)) {
                            cell_err_str = "邮箱格式错误";
                        }
                    }else if("status".equals(excel_key)){
                        if("在职".equals(cell_str)) {
                            cell_str = "1";
                        }else if("离职".equals(cell_str)) {
                            cell_str = "0";
                        }else {
                            cell_err_str = "状态的数据格式错误：只能为在职或离职";
                        }
                    }
                    if("".equals(cell_err_str) && !has_error) {
                        //为了效率，当检测不通过时不再组装具体数据
                        user_data.put(excel_key, cell_str);
                    }
                }
                if(!"".equals(cell_err_str)) {
                    has_error = true;
                    err_info.add(new String[]{excel_index, cell_err_str});
                }
            }
            if(!id_num_repeat && null != excel_row.get(1) && !"".equals(excel_row.get(1).toString().trim())) {
                //组装有效的数据
                String id_num = excel_row.get(1).toString().trim();
                if(has_error) {
                    if(!user_data.containsKey("index")) {
                        user_data.put("index", excel_index);
                    }
                    serialize_data.put(id_num, user_data);
                }else {
                    serialize_data.put(id_num, user_data);
                }
            }
        }

        //用户id_num的存在检测
        List<String> excel_id_num = new ArrayList<String>(serialize_data.keySet());
        List<String> excel_right_id_num = userService.getIdNumByIdNum(excel_id_num);
        excel_right_id_num.retainAll(excel_id_num); //交集
        if(0 < excel_right_id_num.size()) {
            has_error = true;
            for(int i_index = 0; i_index < excel_right_id_num.size(); i_index ++) {
                String id_num = excel_id_num.get(i_index);
                err_info.add(new String[]{serialize_data.get(id_num).get("index"), "工号"+id_num+"的用户已存在"});
            }
        }

        if(has_error) {
            //按行的序号排序
            Collections.sort(err_info, new Comparator<String[]>() {
                @Override
                public int compare(String[] o1, String[] o2) {
                    try {
                        return (Double.parseDouble(o1[0]) > Double.parseDouble(o2[0])) ? 1 : -1;
                    }catch (Exception e) {
                        return o1[0].compareTo(o2[0]);
                    }
                }
            });
            throw exceptionManager.create("File004", err_info);
        }
        return serialize_data;
    }

    public List<String> getUserExcelTitles() {
        return new ArrayList<String>(){{
            add("序号");add("工号");add("姓名");add("出生日期");add("性别");add("电话");add("邮箱");add("备注");add("状态");
        }};
    }
    public List<String> getUserExcelKeys() {
        return new ArrayList<String>(){{
            add("index");add("id_num");add("name");add("birthdate");add("sex");add("phone");add("email");add("remark");add("status");
        }};
    }

    public int getUserExcelTemplate(HttpServletResponse response) throws Exception {
        ExcelData excelData = new ExcelData();
        excelData.setName("user");
        excelData.setTitles(this.getUserExcelTitles());
        ExportExcelUtils.exportExcel(response, "user_template.xlsx", excelData);
        return 1;
    }

    public int editCompony(Company company) {
        return companyService.edit(company);
    }

    public int editTheme(Theme new_theme) {
        return themeService.setTheme(new_theme);
    }

    public Admin getSelf(Integer admin_id) {
        return adminExtendMapper.selectByPrimaryKey(admin_id);
    }
}
